/**
 * @file rtos_freertos.c
 * @author YangSL (dalin@main.com)
 * @brief 
 * @version 0.0.1
 * @date 2022-09-23
 * 
 * @copyright Copyright (c) 2022
 * 
 */

#include "kernel.h"
#include "semphr.h"
#include "queue.h"
#include "bsp_can_bus.h"

static func_kernel_init s_initProcess = 0;
static void task_init(void *pdata)
{
	if (s_initProcess)
	{
		s_initProcess();
	}
	vTaskDelete(NULL);
	
}

/**
 * @brief 创建开始任务
 * 
 * @param init 
 */
void kernel_init(func_kernel_init init)
{
	s_initProcess = init;
	kernel_task_create(task_init,"init",KERNEL_TASK_INIT_PRIO,KERNEL_TASK_INIT_STACK,NULL);
}

/**
 * @brief 开始任务调度器
 * 
 */
void kernel_start(void)
{
	vTaskStartScheduler();
}

uint32 kernel_sysclk(void)
{
    return configCPU_CLOCK_HZ;
}
/**
 * @brief 创建任务
 * 
 * @param task 
 * @param name 
 * @param prio 
 * @param stkSize 
 * @param attr 
 * @return task_t 
 */
task_t kernel_task_create(void   (*task)(void*),const char* name, prio_t prio, int stkSize,void* attr)
{
	TaskHandle_t handle;
	if(pdTRUE != xTaskCreate(task,name,stkSize,NULL,prio,&handle))
	{
//		TRACE_ERR("create task error!");
		return 0;
	}
	return (task_t)handle;
}

/**
 * @brief 删除任务
 * 
 * @param taskID 
 */
void kernel_task_cancel(task_t taskID)
{
	vTaskDelete((TaskHandle_t)taskID);
}

/**
 * @brief 获取任务信息
 * 
 * @param taskID 
 */
void kernel_task_info(task_t taskID)
{
    #if configUSE_TRACE_FACILITY
    TaskStatus_t xTaskDetails;
    TaskHandle_t xHandle = (TaskHandle_t)taskID;
    if (xHandle)
    {
        stack_t freeSize = uxTaskGetStackHighWaterMark(xHandle);
        freeSize = freeSize*sizeof(stack_t);
        vTaskGetInfo(xHandle, &xTaskDetails, pdTRUE, eInvalid);
        KPRINTF("task[%2d:%-16s] state:%d, stack total(----) used(----) free(%4d) usage:----"NEW_LINE,
                 xTaskDetails.xTaskNumber,xTaskDetails.pcTaskName,xTaskDetails.eCurrentState, freeSize);
	}
    else
    {
        KPRINTF("task[%2d: not exist] stack total(----) used(----) free(----) usage:----"NEW_LINE,taskID);
    }
    #endif
}

void* kernel_malloc(uint32 size)
{
    return pvPortMalloc(size);
}

void kernel_free(void* mem)
{
    vPortFree(mem);
}

void kernel_sleep(tick_t ticks)
{
    vTaskDelay(ticks);
}

tick_t kernel_gettime(void)
{
    return xTaskGetTickCount();
}

/**
 * @brief 进入临界保护
 * 
 */
void kernel_critical_enter()
{
    if(IS_IRQ())
    {
        taskENTER_CRITICAL_FROM_ISR();
    }
    else
    {
        taskENTER_CRITICAL();
    }
}

/**
 * @brief 退出临界保护
 * 
 */
void kernel_critical_exit()
{
    if(IS_IRQ())
    {
        uint32 mask=0;
        taskEXIT_CRITICAL_FROM_ISR(mask);
    }
    else
    {
        taskEXIT_CRITICAL();
    }
}

/**
 * @brief 发送任务通知
 * 
 * @param taskID 
 * @return true 
 * @return false 
 */
bool kernel_notify_send(task_t taskID)
{
    TaskHandle_t xHandle = (TaskHandle_t)taskID;
    if (IS_IRQ())
    {
        vTaskNotifyGiveFromISR(xHandle,NULL);
        return true;
    }
    else
    {
        if(xTaskNotifyGive(xHandle)==pdPASS)
        {
            return true;
        }
    }
    return false;
}

/**
 * @brief 接收任务通知
 * 
 * @param msTimeout 
 * @return uint32 
 */
uint32 kernel_notify_recv(sint32 msTimeout)
{
    return ulTaskNotifyTake(pdTRUE,msTimeout/SYSTEM_TICK_MS);
}

mutex_t kernel_mutex_init(void)
{
    SemaphoreHandle_t mutex = xSemaphoreCreateMutex();
    return (mutex_t)mutex;
}
void kernel_mutex_lock(mutex_t mutex)
{
    SemaphoreHandle_t sem = (SemaphoreHandle_t)mutex;
    if (sem!=NULL)
    {
        xSemaphoreTake(sem,-1);
    }
}
void kernel_mutex_unlock(mutex_t mutex)
{
    SemaphoreHandle_t sem = (SemaphoreHandle_t)mutex;
    if (sem!=NULL)
    {
        xSemaphoreGive(sem);
    }
}

/**
 * @brief 创建信号量
 * 
 * @param mqSize 
 * @param msgSize 
 * @return msgqueue_t 
 */
msgqueue_t kernel_mq_init(uint32 mqSize, uint32 msgSize)
{
    return (msgqueue_t)xQueueCreate(mqSize,msgSize);
}

/**
 * @brief 发送信号量
 * 
 * @param mq 
 * @param msg 
 * @param msTimeout 
 * @return true 
 * @return false 
 */
bool kernel_mq_send(msgqueue_t mq, void* msg, sint32 msTimeout)
{
	CanMessage *view_msg = (CanMessage*)msg;
    if (mq)
    {
        if (IS_IRQ())
        {
            if(xQueueSendFromISR((QueueHandle_t)mq, msg, NULL)==pdTRUE)
            {
                return true;
            }
            return false;
        }
        msTimeout = MAX(-1,msTimeout);
        switch(msTimeout){
        case -1:
            if(xQueueSend((QueueHandle_t)mq, msg, -1)==pdTRUE)
            {
                return true;
            }
            break;
        default:
            if(xQueueSend((QueueHandle_t)mq, msg, msTimeout/SYSTEM_TICK_MS)==pdTRUE)
            {
                return true;
            }
            break;
        }
    }
    return false;
}

/**
 * @brief 接收信号量
 * 
 * @param mq 
 * @param msg 
 * @param msTimeout 
 * @return true 
 * @return false 
 */
bool kernel_mq_recv(msgqueue_t mq, void* msg, sint32 msTimeout)
{
    if (mq)
    {
        if (IS_IRQ())
        {
            if(xQueueReceiveFromISR((QueueHandle_t)mq, msg, NULL)==pdTRUE)
            {
                return true;
            }
            return false;
        }
        msTimeout = MAX(-1,msTimeout);
        switch(msTimeout){
        case -1:
            if(xQueueReceive((QueueHandle_t)mq, msg, -1)==pdTRUE)
            {
                return true;
            }
            break;
        default:
            if(xQueueReceive((QueueHandle_t)mq, msg, msTimeout/SYSTEM_TICK_MS)==pdTRUE)
            {
                return true;
            }
            break;
        }
    }
    return false;
}

uint32 kernel_mq_size(msgqueue_t mq)
{
    return uxQueueMessagesWaiting((QueueHandle_t)mq);
}

sem_t kernel_sem_init(uint32 max)
{
    if (max==0)
    {
        return (sem_t)xSemaphoreCreateBinary();
    }
    return (sem_t)xSemaphoreCreateCounting(max,0);
}


bool kernel_sem_post(sem_t sem, sint32 msTimeout)
{
    if (sem)
    {
        if (IS_IRQ())
        {
            if(xSemaphoreGiveFromISR((QueueHandle_t)sem, NULL)==pdTRUE)
            {
                return true;
            }
            return false;
        }
        msTimeout = MAX(-1,msTimeout);
        switch(msTimeout){
        case -1:
            if(xSemaphoreGive((QueueHandle_t)sem)==pdTRUE)
            {
                return true;
            }
            break;
        default:
            if(xQueueGenericSend((QueueHandle_t)sem, NULL,msTimeout/SYSTEM_TICK_MS,0)==pdTRUE)
            {
                return true;
            }
            break;
        }
    }
    return false;
}

/**
 * @brief 等待信号量
 * 
 * @param sem 
 * @param msTimeout 
 * @return true 
 * @return false 
 */
bool kernel_sem_wait(sem_t sem, sint32 msTimeout)
{
    if (sem)
    {
        if (IS_IRQ())
        {
            if(xSemaphoreTakeFromISR((QueueHandle_t)sem, NULL)==pdTRUE)
            {
                return true;
            }
            return false;
        }
        msTimeout = MAX(-1,msTimeout);
        switch(msTimeout){
        case -1:
            if(xSemaphoreTake((QueueHandle_t)sem, -1)==pdTRUE)
            {
                return true;
            }
            break;
        default:
            if(xSemaphoreTake((QueueHandle_t)sem, msTimeout/SYSTEM_TICK_MS)==pdTRUE)
            {
                return true;
            }
            break;
        }
    }
    return false;
}
